feat(output): add basic opentelemetry output#971
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR adds an optional OpenTelemetry (OTLP) logging output to fact, gated behind an ChangesOpenTelemetry Output Feature
CI/CD and Build Infrastructure
Estimated code review effort: 4 (Complex) | ~75 minutes Sequence Diagram(s)sequenceDiagram
participant EventLoop as output::start
participant OtelClient as otel::Client
participant Exporter as OTLP LogExporter
participant Collector as OTLP/Loki Endpoint
EventLoop->>OtelClient: subscribe via oneshot handshake
OtelClient->>OtelClient: receive Event from broadcast
OtelClient->>OtelClient: convert Event to AnyValue LogRecord
OtelClient->>Exporter: emit log record
Exporter->>Collector: POST /v1/logs (protobuf)
sequenceDiagram
participant CI as ci.yml
participant Build as container-build.yml
participant Registry as Quay Registries
CI->>Build: workflow_call (tag-suffix, make-target)
Build->>Build: vars job computes image tags
Build->>Registry: push stackrox-io image (amd64/arm64)
Build->>Registry: push rhacs-eng retagged image
Build->>Registry: create/push multi-arch manifests
Build-->>CI: output tag
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #971 +/- ##
==========================================
+ Coverage 32.64% 32.95% +0.30%
==========================================
Files 21 21
Lines 2916 2971 +55
Branches 2916 2971 +55
==========================================
+ Hits 952 979 +27
- Misses 1961 1989 +28
Partials 3 3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
229cd7d to
8bb3067
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/event.py (1)
298-317: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
.match()doesn't anchor at the end of the string.
expected.match(actual)only checks thatactualstarts with a match forexpected; a longeractualvalue with unexpected trailing characters would still be considered a match. Usefullmatch()for exact validation of regex-based expectations.🐛 Proposed fix
- if not isinstance(actual, str) or not expected.match(actual): + if not isinstance(actual, str) or not expected.fullmatch(actual):🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/event.py` around lines 298 - 317, The regex check in _diff_path currently uses expected.match(actual), which allows extra trailing characters to slip through. Update the Pattern branch in _diff_path to use fullmatch() instead so regex-based expectations must match the entire actual path, while keeping the existing non-regex equality behavior unchanged.
🧹 Nitpick comments (5)
.github/workflows/container-build.yml (2)
25-28: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winConsider
persist-credentials: falseon checkout steps.zizmor's artipacked finding notes these
actions/checkout@v4steps don't setpersist-credentials: false, leaving the ambientGITHUB_TOKENin.git/configfor the remainder of the job — including duringcargo build/podman build, which execute third-party build scripts.🔒 Suggested fix
- uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 + persist-credentials: falseAlso applies to: 54-56
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/container-build.yml around lines 25 - 28, The checkout steps using actions/checkout@v4 currently leave the ambient GITHUB_TOKEN persisted in .git/config, which can leak into later cargo build and podman build steps. Update each checkout block in the workflow to set persist-credentials to false, including the other checkout occurrence referenced by the review, while keeping the existing submodules and fetch-depth settings in place.Source: Linters/SAST tools
33-35: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winHoist interpolated expressions into
env:to avoid template injection.zizmor flags direct
${{ inputs.tag-suffix }},${{ inputs.make-target }}, and${{ needs.vars.outputs.* }}interpolation insiderun:blocks (lines 33-35, 59, 98-102, 120-124) as template-injection risk. Even though these values currently originate from static strings inci.yml, the canonical mitigation is to pass them through a step-levelenv:block and reference them as shell variables, so the pattern remains safe if these inputs are ever driven by less-trusted values.🔒 Example fix for the `vars` step
- id: vars + env: + TAG_SUFFIX: ${{ inputs.tag-suffix }} run: | cat << EOF >> "$GITHUB_OUTPUT" - tag=$(make tag)${{ inputs.tag-suffix }} - stackrox-io-image=$(make image-name)${{ inputs.tag-suffix }} - rhacs-eng-image=$(FACT_REGISTRY="quay.io/rhacs-eng/fact" make image-name)${{ inputs.tag-suffix }} + tag=$(make tag)${TAG_SUFFIX} + stackrox-io-image=$(make image-name)${TAG_SUFFIX} + rhacs-eng-image=$(FACT_REGISTRY="quay.io/rhacs-eng/fact" make image-name)${TAG_SUFFIX} EOFSimilarly for line 59 (
env: MAKE_TARGET: ${{ inputs.make-target }}thenrun: DOCKER=podman make "${MAKE_TARGET}") and the manifest steps (98-102, 120-124), which interpolateneeds.vars.outputs.*directly.Also applies to: 59-59, 98-102, 120-124
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/container-build.yml around lines 33 - 35, The workflow steps that build image tags and run make targets are interpolating GitHub expressions directly inside run blocks, which is the template-injection risk flagged by zizmor. Move the affected values from inputs.tag-suffix, inputs.make-target, and needs.vars.outputs.* into step-level env entries, then reference those shell variables inside the run commands. Apply this pattern in the tag/image-name step, the MAKE_TARGET step, and the manifest-related steps so the logic stays the same but the expressions are no longer expanded directly in shell scripts.Source: Linters/SAST tools
tests/conftest.py (1)
70-100: 🩺 Stability & Availability | 🔵 TrivialFixed OTLP port may conflict under parallel test execution.
OtlpServer.serve()defaults to a hardcoded port (4318), mirroring the existing fixed-port pattern forGrpcServer(9999). If these tests are ever run withpytest-xdistor otherwise in parallel across workers, both fixed ports could collide across concurrently-running test processes. Not a regression introduced by this diff, but doubling the fixed-port surface (grpc + otlp) is worth tracking if parallelization is a goal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/conftest.py` around lines 70 - 100, The server fixture currently hardcodes OTLP to a fixed port via OtlpServer.serve(), which can collide when tests run in parallel. Update the server setup in pytest_generate_tests/server so OtlpServer can be started with a worker-unique or free port (similar to how GrpcServer is selected by mode), and make the fixture pass that port through instead of relying on the default 4318. Ensure the change is localized around _get_output_modes, pytest_generate_tests, and server so each test process gets an isolated OTLP endpoint.tests/server.py (1)
41-58: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win
ThreadPoolExecutoris never shut down.Neither
GrpcServer.stop()norOtlpServer.stop()callsself.executor.shutdown(). Each test using theserverfixture creates a freshEventServersubclass instance with its own 2-worker pool that's never explicitly released, leaking idle threads across the test session (they'll only terminate at interpreter exit).♻️ Proposed fix
def stop(self): """Stop the gRPC server.""" self.server.stop(1) self.running.clear() + self.executor.shutdown(wait=False)and similarly for
OtlpServer.stop().🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/server.py` around lines 41 - 58, `EventServer` creates a `ThreadPoolExecutor` in its constructor but the pool is never released, so update the shutdown path in both `GrpcServer.stop()` and `OtlpServer.stop()` to call `self.executor.shutdown()` after stopping the server work. Make the cleanup part of the existing `stop` methods so each `EventServer` subclass instance properly tears down its worker threads when the test fixture finishes.fact/src/event/process.rs (1)
45-57: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick winInconsistent attribute key naming:
exec_pathvsexe_path.
Lineage'sexe_pathfield is emitted under the key"exec_path", while the siblingProcessconversion (line 259-261 in this same file) emits the analogous field under"exe_path". Since these are exported as OTLP log attributes consumed by external tooling (Grafana/Loki dashboards per this PR's docs), inconsistent naming for the same semantic field across nested maps will confuse queries/dashboards built against the OTel schema.🔧 Suggested fix
impl From<Lineage> for opentelemetry::logs::AnyValue { fn from(value: Lineage) -> Self { AnyValue::Map(Box::new(HashMap::from([ ("uid".into(), value.uid.into()), ( - "exec_path".into(), + "exe_path".into(), value.exe_path.to_string_lossy().to_string().into(), ), ]))) } }This isn't exercised by the current Python OTLP test server (which doesn't parse
lineage), so it wouldn't be caught by CI as-is.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@fact/src/event/process.rs` around lines 45 - 57, The `Lineage` OTEL conversion is exporting the `exe_path` field under a different attribute name than the sibling `Process` conversion, causing inconsistent log schema. Update the `From<Lineage> for opentelemetry::logs::AnyValue` implementation in `process.rs` so the map key matches the existing `Process` export naming (`exe_path`) and keep the attribute naming consistent across both conversions for downstream queries and dashboards.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@fact/src/output/otel.rs`:
- Around line 65-70: The LogExporter setup in otel initialization is panicking
on build failure via expect, which should be converted to normal error handling.
Update the LogExporter::builder() chain in the otel initialization path to
propagate the ExporterBuildError with ? or a context-wrapped error instead of
expect, so failures flow through the existing Result-based path rather than
crashing.
In `@fact/src/output/stdout.rs`:
- Around line 27-29: The subscription handshake in the stdout output path can
panic if the orchestrator is shutting down and the oneshot/channel is already
closed. In the task that uses std::sync::oneshot::channel and
self.subscriber.send(tx), replace both unwrap() calls with graceful error
handling: if sending the subscription request fails or rx.await returns an
error, log the failure and return early instead of panicking. Use the existing
stdout subscription flow around the send/receive handshake to locate the fix.
In `@tests/utils.py`:
- Around line 61-68: The string-quoting logic in the helper that builds
shell-safe literals has an unsafe fallback in the single-quote path for values
containing backslashes or quotes plus backticks or dollar signs. Update the
quoting branch in the relevant utility function to route those cases through the
double-quoted form instead, and make that branch escape backslash, double quote,
backtick, and dollar-sign characters so the value is always treated literally.
Keep the single-quoted fallback only for strings that do not need those extra
escapes.
---
Outside diff comments:
In `@tests/event.py`:
- Around line 298-317: The regex check in _diff_path currently uses
expected.match(actual), which allows extra trailing characters to slip through.
Update the Pattern branch in _diff_path to use fullmatch() instead so
regex-based expectations must match the entire actual path, while keeping the
existing non-regex equality behavior unchanged.
---
Nitpick comments:
In @.github/workflows/container-build.yml:
- Around line 25-28: The checkout steps using actions/checkout@v4 currently
leave the ambient GITHUB_TOKEN persisted in .git/config, which can leak into
later cargo build and podman build steps. Update each checkout block in the
workflow to set persist-credentials to false, including the other checkout
occurrence referenced by the review, while keeping the existing submodules and
fetch-depth settings in place.
- Around line 33-35: The workflow steps that build image tags and run make
targets are interpolating GitHub expressions directly inside run blocks, which
is the template-injection risk flagged by zizmor. Move the affected values from
inputs.tag-suffix, inputs.make-target, and needs.vars.outputs.* into step-level
env entries, then reference those shell variables inside the run commands. Apply
this pattern in the tag/image-name step, the MAKE_TARGET step, and the
manifest-related steps so the logic stays the same but the expressions are no
longer expanded directly in shell scripts.
In `@fact/src/event/process.rs`:
- Around line 45-57: The `Lineage` OTEL conversion is exporting the `exe_path`
field under a different attribute name than the sibling `Process` conversion,
causing inconsistent log schema. Update the `From<Lineage> for
opentelemetry::logs::AnyValue` implementation in `process.rs` so the map key
matches the existing `Process` export naming (`exe_path`) and keep the attribute
naming consistent across both conversions for downstream queries and dashboards.
In `@tests/conftest.py`:
- Around line 70-100: The server fixture currently hardcodes OTLP to a fixed
port via OtlpServer.serve(), which can collide when tests run in parallel.
Update the server setup in pytest_generate_tests/server so OtlpServer can be
started with a worker-unique or free port (similar to how GrpcServer is selected
by mode), and make the fixture pass that port through instead of relying on the
default 4318. Ensure the change is localized around _get_output_modes,
pytest_generate_tests, and server so each test process gets an isolated OTLP
endpoint.
In `@tests/server.py`:
- Around line 41-58: `EventServer` creates a `ThreadPoolExecutor` in its
constructor but the pool is never released, so update the shutdown path in both
`GrpcServer.stop()` and `OtlpServer.stop()` to call `self.executor.shutdown()`
after stopping the server work. Make the cleanup part of the existing `stop`
methods so each `EventServer` subclass instance properly tears down its worker
threads when the test fixture finishes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Enterprise
Run ID: 6070caf3-6f12-4fe2-99cd-d0c9f8b532da
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (46)
.github/workflows/ci.yml.github/workflows/container-build.yml.github/workflows/integration-tests.yml.github/workflows/konflux-tests.ymlContainerfileMakefileansible/run-tests.ymldocs/otel/grafana-dashboard-provider.yamldocs/otel/grafana-datasource.yamldocs/otel/grafana-fact-dashboard.jsondocs/otel/loki-config.yamldocs/otel/otel.mdfact/Cargo.tomlfact/src/config/mod.rsfact/src/config/reloader.rsfact/src/config/tests.rsfact/src/event/mod.rsfact/src/event/process.rsfact/src/lib.rsfact/src/metrics/mod.rsfact/src/output/grpc.rsfact/src/output/mod.rsfact/src/output/otel.rsfact/src/output/stdout.rstests/Makefiletests/conftest.pytests/event.pytests/requirements.txttests/server.pytests/test_config_hotreload.pytests/test_editors/test_nvim.pytests/test_editors/test_sed.pytests/test_editors/test_vi.pytests/test_editors/test_vim.pytests/test_file_open.pytests/test_misc.pytests/test_path_chmod.pytests/test_path_chown.pytests/test_path_mkdir.pytests/test_path_rename.pytests/test_path_rmdir.pytests/test_path_unlink.pytests/test_rate_limit.pytests/test_wildcard.pytests/test_xattr.pytests/utils.py
| let (tx, rx) = oneshot::channel(); | ||
| self.subscriber.send(tx).await.unwrap(); | ||
| let mut rx = rx.await.unwrap(); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Handle subscription handshake failure gracefully instead of unwrap().
If the output orchestrator's loop has already exited (e.g. during shutdown), subs_rx/the oneshot sender may be dropped, making these .unwrap()s panic in the spawned task. Prefer logging and returning, matching the graceful termination used elsewhere.
🛡️ Proposed fix
- let (tx, rx) = oneshot::channel();
- self.subscriber.send(tx).await.unwrap();
- let mut rx = rx.await.unwrap();
+ let (tx, rx) = oneshot::channel();
+ if self.subscriber.send(tx).await.is_err() {
+ info!("Output orchestrator gone, stopping stdout output...");
+ return;
+ }
+ let mut rx = match rx.await {
+ Ok(rx) => rx,
+ Err(_) => {
+ info!("Failed to obtain event receiver, stopping stdout output...");
+ return;
+ }
+ };📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let (tx, rx) = oneshot::channel(); | |
| self.subscriber.send(tx).await.unwrap(); | |
| let mut rx = rx.await.unwrap(); | |
| let (tx, rx) = oneshot::channel(); | |
| if self.subscriber.send(tx).await.is_err() { | |
| info!("Output orchestrator gone, stopping stdout output..."); | |
| return; | |
| } | |
| let mut rx = match rx.await { | |
| Ok(rx) => rx, | |
| Err(_) => { | |
| info!("Failed to obtain event receiver, stopping stdout output..."); | |
| return; | |
| } | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@fact/src/output/stdout.rs` around lines 27 - 29, The subscription handshake
in the stdout output path can panic if the orchestrator is shutting down and the
oneshot/channel is already closed. In the task that uses
std::sync::oneshot::channel and self.subscriber.send(tx), replace both unwrap()
calls with graceful error handling: if sending the subscription request fails or
rx.await returns an error, log the failure and return early instead of
panicking. Use the existing stdout subscription flow around the send/receive
handshake to locate the fix.
| if re.search(r'[^a-zA-Z0-9_.:\-/+@\]]', s): | ||
| # Backslash and single-quote cannot appear in single-quoted | ||
| # strings in Rust's shlex, use double-quoting instead. | ||
| if ('\\' in s or "'" in s) and '`' not in s and '$' not in s: | ||
| escaped = s.replace('\\', '\\\\').replace('"', '\\"') | ||
| return f'"{escaped}"' | ||
| escaped = s.replace("'", "\\'") | ||
| return f"'{escaped}'" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Broken single-quote fallback for strings with both a quote and backtick/$.
When a string contains a backslash or ' and also contains ` or $, the code falls through to the single-quote branch (s.replace("'", "\\'")). This contradicts the function's own comment: backslash has no escaping power inside single-quoted shell strings, so \' does not produce a literal quote — it just embeds a literal backslash and then the string is prematurely terminated by the unescaped '. The rest of the string (containing the backtick/$) ends up unquoted, exposing it to command substitution/expansion instead of being treated literally.
The double-quote branch already handles \ and "; extending it to also escape ` and $ removes the need for this unsafe fallback entirely.
🐛 Proposed fix
if re.search(r'[^a-zA-Z0-9_.:\-/+@\]]', s):
- # Backslash and single-quote cannot appear in single-quoted
- # strings in Rust's shlex, use double-quoting instead.
- if ('\\' in s or "'" in s) and '`' not in s and '$' not in s:
- escaped = s.replace('\\', '\\\\').replace('"', '\\"')
+ # Backslash and single-quote cannot appear in single-quoted
+ # strings in Rust's shlex, use double-quoting instead.
+ if '\\' in s or "'" in s:
+ escaped = (
+ s.replace('\\', '\\\\')
+ .replace('"', '\\"')
+ .replace('`', '\\`')
+ .replace('$', '\\$')
+ )
return f'"{escaped}"'
escaped = s.replace("'", "\\'")
return f"'{escaped}'"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if re.search(r'[^a-zA-Z0-9_.:\-/+@\]]', s): | |
| # Backslash and single-quote cannot appear in single-quoted | |
| # strings in Rust's shlex, use double-quoting instead. | |
| if ('\\' in s or "'" in s) and '`' not in s and '$' not in s: | |
| escaped = s.replace('\\', '\\\\').replace('"', '\\"') | |
| return f'"{escaped}"' | |
| escaped = s.replace("'", "\\'") | |
| return f"'{escaped}'" | |
| if re.search(r'[^a-zA-Z0-9_.:\-/+@\]]', s): | |
| # Backslash and single-quote cannot appear in single-quoted | |
| # strings in Rust's shlex, use double-quoting instead. | |
| if '\\' in s or "'" in s: | |
| escaped = ( | |
| s.replace('\\', '\\\\') | |
| .replace('"', '\\"') | |
| .replace('`', '\\`') | |
| .replace('$', '\\$') | |
| ) | |
| return f'"{escaped}"' | |
| escaped = s.replace("'", "\\'") | |
| return f"'{escaped}'" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/utils.py` around lines 61 - 68, The string-quoting logic in the helper
that builds shell-safe literals has an unsafe fallback in the single-quote path
for values containing backslashes or quotes plus backticks or dollar signs.
Update the quoting branch in the relevant utility function to route those cases
through the double-quoted form instead, and make that branch escape backslash,
double quote, backtick, and dollar-sign characters so the value is always
treated literally. Keep the single-quoted fallback only for strings that do not
need those extra escapes.
f4dda9f to
a52c44e
Compare
a52c44e to
b915ce8
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
fact/src/output/grpc.rs (1)
207-259: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftKeep the broadcast receiver alive across reconnects. Re-subscribing inside the reconnect loop creates a gap: events published while the gRPC stream is down are never delivered to this client, and
Laggedonly covers backlog on an already-subscribed receiver. If that loss is intentional, add a metric for the gap; otherwise reuse the receiver across reconnects.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@fact/src/output/grpc.rs` around lines 207 - 259, The reconnect logic in run currently re-subscribes on every loop iteration, which drops any events published while the gRPC stream is down. Update the FileActivityServiceClient subscription flow in run so the broadcast receiver is created once and kept alive across reconnects instead of calling self.subscriber.send(tx) each retry; if intentional loss is expected, add a metric for the reconnect gap.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@fact/src/output/grpc.rs`:
- Around line 207-259: The reconnect logic in run currently re-subscribes on
every loop iteration, which drops any events published while the gRPC stream is
down. Update the FileActivityServiceClient subscription flow in run so the
broadcast receiver is created once and kept alive across reconnects instead of
calling self.subscriber.send(tx) each retry; if intentional loss is expected,
add a metric for the reconnect gap.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Enterprise
Run ID: a43a125f-8af4-4b1a-b4ff-05bf76a151bd
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
CHANGELOG.mdfact/Cargo.tomlfact/src/config/mod.rsfact/src/config/reloader.rsfact/src/config/tests.rsfact/src/event/mod.rsfact/src/event/process.rsfact/src/lib.rsfact/src/metrics/mod.rsfact/src/output/grpc.rsfact/src/output/mod.rsfact/src/output/otel.rs
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (10)
- fact/src/lib.rs
- fact/src/metrics/mod.rs
- fact/src/config/tests.rs
- fact/src/config/mod.rs
- fact/src/output/otel.rs
- fact/src/output/mod.rs
- fact/Cargo.toml
- fact/src/event/mod.rs
- fact/src/event/process.rs
- fact/src/config/reloader.rs
This output allows exporting file activity events as opentelemetry logs via otlp to be collected by compatible systems. The output is gated behind the "otel" feature, which allows regular fact builds to keep using just the gRPC and stodout outputs, no additional dependencies. WIP
b915ce8 to
4214811
Compare
Description
This output allows exporting file activity events as opentelemetry logs via otlp to be collected by compatible systems.
Checklist
Automated testing
If any of these don't apply, please comment below.
Testing Performed
Tested pushing events to Loki and visualizing events in Grafana with the provided documentation.
Summary by CodeRabbit
New Features
Bug Fixes